package com.music.glide.load.model

import android.net.Uri
import com.music.glide.load.KKey
import com.music.glide.util.KPreconditions
import java.net.MalformedURLException
import java.net.URL
import java.security.MessageDigest

class KGlideUrl : KKey {

    private var url: URL? = null
    private var stringUrl: String? = null
    private var headers: KHeaders = KHeaders.DEFAULT
    private var safeStringUrl: String? = null
    private var safeUrl: URL? = null
    @Volatile
    private var cacheKeyBytes: ByteArray? = null
    private var hasCode = 0

    constructor(url: String, headers: KHeaders = KHeaders.DEFAULT) {
        this.stringUrl = KPreconditions.checkNotEmpty(url)
        this.headers = headers
    }

    constructor(url: URL, headers: KHeaders = KHeaders.DEFAULT) {
        this.url = url
        this.headers = headers
    }

    @Throws(MalformedURLException::class)
    fun toURL():URL {
        return getSafeUrl()
    }

    fun getSafeUrl():URL {
        if (safeUrl == null) {
            safeUrl = URL(getSafeStringUrl())
        }
        return safeUrl!!
    }

    fun toStringUrl() = getSafeStringUrl()

    private fun getSafeStringUrl():String {
        if (safeStringUrl.isNullOrEmpty()) {
            var unsafeStringUrl = stringUrl
            if (unsafeStringUrl.isNullOrEmpty()) {
                unsafeStringUrl = KPreconditions.checkNotNull(url).toString()
            }
            safeStringUrl = Uri.encode(unsafeStringUrl, ALLOWED_URI_CHARS)
        }
        return safeStringUrl!!
    }

    fun getHeader() = headers.getHeader()

    fun getCacheKey():String {
        return stringUrl ?: KPreconditions.checkNotNull(url).toString()
    }

    private fun getCacheKeyBytes():ByteArray{
        if (cacheKeyBytes == null){
            cacheKeyBytes = getCacheKey().toByteArray()
        }
        return cacheKeyBytes!!
    }

    override fun updateDiskCacheKey(messageDigest: MessageDigest) {
        messageDigest.update(getCacheKeyBytes())
    }

    override fun toString(): String {
        return getCacheKey()
    }

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        if (other is KGlideUrl) {
            return getCacheKey() == other.getCacheKey() && headers == other.headers
        }
        return false
    }

    override fun hashCode(): Int {
        var result = headers.hashCode()
        result = 31 * result + (getCacheKey().hashCode())
        return result
    }

    companion object {

        private const val ALLOWED_URI_CHARS = "@#&=*+-_.,:!?()/~'%;$"

    }

}